﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;

namespace Player
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        SessionBase m_session;
        public MainWindow()
        {
            InitializeComponent();

            m_session = new UnixSession(App.ConnectionString, new Guid(App.SessionId));

            G g = new G(m_session);
            this.DataContext = g;

            m_session.Play(0);
            //this.TrackBar.DataContext = g;
            //this.TimeToolTip.DataContext = g;
        }

        private void Pause_Click(object sender, RoutedEventArgs e)
        {
            if (m_session != null)
            {
                m_session.Pause();
            }
        }

        private void TrackBar_MouseMove(object sender, MouseEventArgs e)
        {
            m_session.Preview(TrackBar.PointerLocation);

            Point position = e.GetPosition(this);
            Point pt = TrackBar.TranslatePoint(new Point(0, 0), this.ToolTipLayer);
            TimeToolTip.SetValue(Canvas.LeftProperty, position.X);
            TimeToolTip.SetValue(Canvas.TopProperty, pt.Y);
        }

        private void TrackBar_MouseEnter(object sender, MouseEventArgs e)
        {
            this.Title = "Visible";
            TimeToolTip.Visibility = Visibility.Visible;
        }

        private void TrackBar_MouseLeave(object sender, MouseEventArgs e)
        {
            this.Title = "Hidden";
            TimeToolTip.Visibility = Visibility.Hidden;
        }

        private void TrackBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!m_session.GotoInProgress)
            {
                Point pos = e.GetPosition(TrackBar);
                m_session.Goto(pos.X / TrackBar.ActualWidth);
            }
        }

        protected override void OnClosed(EventArgs e)
        {
            if (m_session != null)
            {
                m_session.Stop();
            }
            base.OnClosed(e);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            m_session.Play(0);
        }
    }

    public class G : INotifyPropertyChanged
    {
        SessionBase m_session;
        public G(SessionBase session)
        {
            m_session = session;
            m_session.PlayingProgressUpdated += new EventHandler<PlayingProgressUpdatedEventArgs>(session_PlayingProgressUpdated);
            m_session.FrameBufferUpdated += new EventHandler<FrameBufferUpdatedEventArgs>(session_FrameBufferUpdated);
            m_session.ImageChange += new EventHandler<BitmapImageArgs>(session_ImageChange);
        }

        void session_ImageChange(object sender, BitmapImageArgs e)
        {
            Image = e.Image;
        }

        void session_FrameBufferUpdated(object sender, FrameBufferUpdatedEventArgs e)
        {
            if (e.StartFrame != null)
            {
                double bufferStartTime = m_session.GetElapsedTime(e.StartFrame.TimeStamp).TotalMilliseconds;
                BufferStart = bufferStartTime / m_session.Length;
            }

            if (e.EndFrame != null)
            {
                double bufferEndTime = m_session.GetElapsedTime(e.EndFrame.TimeStamp).TotalMilliseconds;
                BufferEnd = bufferEndTime / m_session.Length;
            }
        }

        void session_PlayingProgressUpdated(object sender, PlayingProgressUpdatedEventArgs e)
        {
            if (!e.FastForward)
            {
                UpdateProgress(e.Frame);
            }
        }

        private void UpdateProgress(FrameBase frame)
        {
            //TimeSpan timeElapsed = m_session.GetElapsedTime(frame.TimeStamp);
            //Progress = timeElapsed.TotalMilliseconds / m_session.Length;
            Progress = (frame.TimeStamp - m_session.Start) / m_session.Length;
            if (Progress >= 1 && m_session.IsPlaying)
            {
                // reset the progress to start point that it can continue to replay the session when user click the "play" button
                Progress = 0;
            }
        }

        private double m_bufferStart;
        public double BufferStart
        {
            get { return m_bufferStart; }
            protected set
            {
                if (m_bufferStart != value)
                {
                    m_bufferStart = value;
                    OnPropertyChanged("BufferStart");
                }
            }
        }

        private double m_bufferEnd;
        public double BufferEnd
        {
            get { return m_bufferEnd; }
            protected set
            {
                if (m_bufferEnd != value)
                {
                    m_bufferEnd = value;
                    OnPropertyChanged("BufferEnd");
                }
            }
        }

        private BitmapSource _image;
        public BitmapSource Image
        {
            get
            {
                return this._image;
            }
            set
            {
                this._image = value;
                OnPropertyChanged("Image");
            }
        }

        private double m_progress;
        public double Progress
        {
            get { return m_progress; }
            protected set
            {
                if (m_progress != value)
                {
                    m_progress = value;
                    OnPropertyChanged("Progress");
                }
            }
        }  protected virtual bool ThrowOnInvalidPropertyName { get; set; }

        private string m_text;
        public string Text
        {
            get { return m_text; }
            set
            {
                if (m_text != value)
                {
                    m_text = value;
                    OnPropertyChanged("Text");
                }
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            var e = new PropertyChangedEventArgs(propertyName);
            PropertyChanged.Invoke(this, e);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            // Verify that the property name matches a real,  
            // public, instance property on this object.
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;

                if (this.ThrowOnInvalidPropertyName)
                    throw new ArgumentException(msg);
                else
                    Debug.Fail(msg);
            }
        }
    }
}